home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-03-29 | 11.3 KB | 451 lines | [TEXT/ttxt] |
- /*
- The fillet plugin generates a set of splines which form a blend between two
- polygon objects. After (manually) setting the direction and starting points
- of each spline, create a Skin object from the group.
-
- Bonus plugins:
- Inflate object - compute average normal at each vertex
- and move outward a specified distance
-
- Derive spline of intersection - draw a spline along the surface of the
- selected object, where it is intersected by the specified cutting object
-
- Send comments, praise, money :-) etc. to:
-
- Jim Hasselbrook
- hassel@bellatlantic.net
-
- This software is provided free, AS IS. Feel free to modify it to suit your needs.
- */
-
-
-
- copy(doc, obj, newname)
- {
- StatusSetText("Copying object", TRUE);
-
- var i;
-
- var pcount = obj->GetPointCount();
- var ecount = obj->GetEdgeCount();
- var tcount = obj->GetTriangleCount();
- var qcount = obj->GetQuadrangleCount();
-
- var newobj = doc->NewPolygonObject(newname, NULL, NULL, pcount, ecount, tcount, qcount);
-
- var t = new(Triangle);
- var q = new(Quadrangle);
- var e = new(Edge);
-
- var mat = new(Matrix);
- obj->GetMg(mat); // obj to world coords
-
- for (i=0; i<pcount; i++) {
- StatusSetBar(i*100.0/pcount, TRUE);
- newobj->SetPoint(i, mat->MulP(obj->GetPoint(i)));
- }
-
- for (i=0; i<ecount; i++) {
- StatusSetBar(i*100.0/ecount, TRUE);
- obj->GetEdge(i, e);
- newobj->SetEdge(i, e);
- }
-
- for (i=0; i<tcount; i++) {
- StatusSetBar(i*100.0/tcount, TRUE);
- obj->GetTriangle(i, t);
- newobj->SetTriangle(i, t);
- }
-
- for (i=0; i<qcount; i++) {
- StatusSetBar(i*100.0/qcount, TRUE);
- obj->GetQuadrangle(i, q);
- newobj->SetQuadrangle(i, q);
- }
-
- newobj->UpdateObject();
- return newobj;
- }
-
- doInflate(doc, obj, amount)
- {
- var pcount = obj->GetPointCount();
- var tcount = obj->GetTriangleCount();
- var qcount = obj->GetQuadrangleCount();
-
- StatusSetText("Copying object", TRUE);
- var newobj = copy(doc, obj, stradd(stradd(obj->GetName(), "+"), tostring(amount)));
-
- if (amount != 0.0)
- {
- var i;
- var norms = new(array, pcount);
- var t = new(Triangle);
- var q = new(Quadrangle);
- var a, b, c, d, norm;
-
- StatusSetText("Calculating normals", TRUE);
-
- for (i=0; i<pcount; i++)
- {
- StatusSetBar(i*100.0/pcount, TRUE);
- norms[i] = vector(0.0, 0.0, 0.0);
- }
-
- for (i=0; i<tcount; i++)
- {
- StatusSetBar(i*100.0/tcount, TRUE);
- newobj->GetTriangle(i, t);
- a = newobj->GetPoint(t->a);
- b = newobj->GetPoint(t->b);
- c = newobj->GetPoint(t->c);
- norm = vnorm(vcross(a-b, a-c));
- norms[t->a] += norm;
- norms[t->b] += norm;
- norms[t->c] += norm;
- }
-
- for (i=0; i<qcount; i++)
- {
- StatusSetBar(i*100.0/qcount, TRUE);
- newobj->GetQuadrangle(i, q);
- a = newobj->GetPoint(q->a);
- b = newobj->GetPoint(q->b);
- c = newobj->GetPoint(q->c);
- d = newobj->GetPoint(q->d);
- norm = vnorm(vcross(a-b, a-c) + vcross(a-c, a-d));
- norms[q->a] += norm;
- norms[q->b] += norm;
- norms[q->c] += norm;
- norms[q->d] += norm;
- }
-
- StatusSetText("Inflating points", TRUE);
- for (i=0; i<pcount; i++)
- {
- StatusSetBar(i*100.0/pcount, TRUE);
- newobj->SetPoint(i, newobj->GetPoint(i) + vnorm(norms[i]) * amount);
- }
- }
- newobj->UpdateObject();
-
- return newobj;
- }
-
- isInside(p,a,b,c)
- {
- var vab = vcross(a-p, b-p);
- var vbc = vcross(b-p, c-p);
- var vca = vcross(c-p, a-p);
-
- // for accuracy, choose component with greatest magnitude
-
- if (abs(vab.x) > abs(vab.y) && (abs(vab.x) > abs(vab.z))) // x
- {
- return (vab.x >= 0.0 && vbc.x >= 0.0 && vca.x >= 0.0) || (vab.x <= 0.0 && vbc.x <= 0.0 && vca.x <= 0.0);
- }
- else if (abs(vab.y) > abs(vab.z)) // y
- {
- return (vab.y >= 0.0 && vbc.y >= 0.0 && vca.y >= 0.0) || (vab.y <= 0.0 && vbc.y <= 0.0 && vca.y <= 0.0);
- }
- else // z
- {
- return (vab.z >= 0.0 && vbc.z >= 0.0 && vca.z >= 0.0) || (vab.z <= 0.0 && vbc.z <= 0.0 && vca.z <= 0.0);
- }
- }
-
- edgeIntersectsTriangle(ea, eb, a, b, c)
- {
- var v = vnorm(vcross(a-b, a-c));
- var w = eb - ea;
- var wv = w * v; // dot product
-
- if (wv) // if zero, edge is || to plane of triangle
- {
- var x = ((a - ea) * v) / wv;
-
- if (0.0 <= x && x <= 1.0) // intersection with plane lies between e->a and e->b
- {
- var p = ea + x * w;
-
- if (isInside(p, a, b, c)) // point lies inside triangle
- {
- return p;
- }
- }
- }
- return NULL;
- }
-
- /*
- Spline point sorting, courtesy of John Detch, 3D Gear
- */
-
- ClosePointSort(obj)
- {
- var sp1=new(SplinePoint),sp2=new(SplinePoint);
- var num=obj->GetPointCount();
- var i,j,last=new(SplinePoint);
- var len,nlen,v=vector(0,0,0);
-
- StatusSetText("Sorting spline points", TRUE);
- for(i=0;i<num;i++){
- obj->GetPoint(i,sp1);
- len=100000000.0;
- for(j=i+1;j<num;j++){
- obj->GetPoint(j,sp2);
- v=sp1->p-sp2->p;
- nlen=vlen(v);
- if(nlen<len){
- last=j;
- len=nlen;
- }
- }
- if(j!=i+1){
- obj->GetPoint(i+1,sp1);
- obj->GetPoint(last,sp2);
- obj->SetPoint(i+1,sp2);
- obj->SetPoint(last,sp1);
- }
- }
- }
-
- /*
- for each edge in objA
- {
- find edges of objA which intersect some polyB of objB, get point of intersection
- }
- */
- cut_A_with_B(doc, group, objA, objB)
- {
- var i, j;
- var splineobj = doc->NewSplineObject("Spline",group,NULL,0);
- var newPoint = new(SplinePoint);
- var info = new(SplineInfo);
- splineobj->GetSplineInfo(info);
- info->closed = TRUE;
- splineobj->SetSplineInfo(info);
-
- var lowerA = vector(0.0, 0.0, 0.0);
- var upperA = vector(0.0, 0.0, 0.0);
- var lowerB = objB->GetBox1();
- var upperB = objB->GetBox2();
-
- var ecountA = objA->GetEdgeCount();
- var tcountB = objB->GetTriangleCount();
- var qcountB = objB->GetQuadrangleCount();
- var e = new(Edge);
- var t = new(Triangle);
- var q = new(Quadrangle);
- var a, b, c, d, ea, eb, p, lastPoint;
-
- var ta = new(array, tcountB);
- var tb = new(array, tcountB);
- var tc = new(array, tcountB);
- var qa = new(array, qcountB);
- var qb = new(array, qcountB);
- var qc = new(array, qcountB);
- var qd = new(array, qcountB);
-
- for (i=0; i<tcountB; i++)
- {
- objB->GetTriangle(i, t);
- ta[i] = objB->GetPoint(t->a);
- tb[i] = objB->GetPoint(t->b);
- tc[i] = objB->GetPoint(t->c);
- }
-
- for (i=0; i<qcountB; i++)
- {
- objB->GetQuadrangle(i, q);
- qa[i] = objB->GetPoint(q->a);
- qb[i] = objB->GetPoint(q->b);
- qc[i] = objB->GetPoint(q->c);
- qd[i] = objB->GetPoint(q->d);
- }
-
- StatusSetText("Finding intersection", TRUE);
- for (i=0; i<ecountA; i++)
- {
- StatusSetBar(i*100.0/ecountA, TRUE);
- objA->GetEdge(i, e);
- ea = objA->GetPoint(e->a);
- eb = objA->GetPoint(e->b);
-
- if ((ea.x < lowerB.x && eb.x < lowerB.x) || (ea.x > upperB.x && eb.x > upperB.x)) continue;
- if ((ea.y < lowerB.y && eb.y < lowerB.y) || (ea.y > upperB.y && eb.y > upperB.y)) continue;
- if ((ea.z < lowerB.z && eb.z < lowerB.z) || (ea.z > upperB.z && eb.z > upperB.z)) continue;
-
- if (ea.x < eb.x) { lowerA.x = ea.x; upperA.x = eb.x; } else { lowerA.x = eb.x; upperA.x = ea.x; }
- if (ea.y < eb.y) { lowerA.y = ea.y; upperA.y = eb.y; } else { lowerA.y = eb.y; upperA.y = ea.y; }
- if (ea.z < eb.z) { lowerA.z = ea.z; upperA.z = eb.z; } else { lowerA.z = eb.z; upperA.z = ea.z; }
-
- for (j=0; j<tcountB; j++)
- {
- a = ta[j]; b = tb[j]; c = tc[j];
-
- if ((a.x < lowerA.x && b.x < lowerA.x && c.x < lowerA.x) ||
- (a.x > upperA.x && b.x > upperA.x && c.x > upperA.x)) continue;
- if ((a.y < lowerA.y && b.y < lowerA.y && c.y < lowerA.y) ||
- (a.y > upperA.y && b.y > upperA.y && c.y > upperA.y)) continue;
- if ((a.z < lowerA.z && b.z < lowerA.z && c.z < lowerA.z) ||
- (a.z > upperA.z && b.z > upperA.z && c.z > upperA.z)) continue;
-
- p = edgeIntersectsTriangle(ea, eb, a, b, c);
- if (p && (!lastPoint || p != lastPoint))
- {
- newPoint->p = p;
- splineobj->AddPoint(newPoint);
- lastPoint = p;
- }
- }
-
- for (j=0; j<qcountB; j++)
- {
- a = qa[j]; b = qb[j]; c = qc[j]; d = qd[j];
-
- if ((a.x < lowerA.x && b.x < lowerA.x && c.x < lowerA.x && d.x < lowerA.x) ||
- (a.x > upperA.x && b.x > upperA.x && c.x > upperA.x && d.x > upperA.x)) continue;
- if ((a.y < lowerA.y && b.y < lowerA.y && c.y < lowerA.y && d.y < lowerA.y) ||
- (a.y > upperA.y && b.y > upperA.y && c.y > upperA.y && d.y > upperA.y)) continue;
- if ((a.z < lowerA.z && b.z < lowerA.z && c.z < lowerA.z && d.z < lowerA.z) ||
- (a.z > upperA.z && b.z > upperA.z && c.z > upperA.z && d.z > upperA.z)) continue;
-
- p = edgeIntersectsTriangle(ea, eb, a, b, c);
- if (p && (!lastPoint || p != lastPoint))
- {
- newPoint->p = p;
- splineobj->AddPoint(newPoint);
- lastPoint = p;
- }
- p = edgeIntersectsTriangle(ea, eb, c, d, a);
- if (p && (!lastPoint || p != lastPoint))
- {
- newPoint->p = p;
- splineobj->AddPoint(newPoint);
- lastPoint = p;
- }
- }
- }
- ClosePointSort(splineobj);
- splineobj->UpdateObject();
- }
-
- inflate(doc)
- {
- var obj = doc->FindFirstActiveObject();
-
- if(!obj || !instanceof(obj,PolygonObject))
- {
- TextDialog("Must select a polygon object!", DLG_OK);
- return;
- }
-
- var d = new (SimpleDialog);
-
- d->SetData(0,"Amount",FIELD_FLOAT,-1000000.0,1000000.0,10.0);
- d->SetTitle("Inflate by Amount");
-
- if (!d->DoDialog()) return FALSE;
-
- var amount = d->GetData(0);
-
- doInflate(doc, obj, amount);
-
- doc->SendMessage(DOCUMENT_CHANGED);
- StatusClear();
- }
-
- intersect(doc)
- {
- var objA = doc->FindFirstActiveObject();
-
- if(!objA || !instanceof(objA, PolygonObject))
- {
- TextDialog("Must select a polygon object!", DLG_OK);
- return;
- }
-
- var d = new (SimpleDialog);
-
- d->SetData(0,"Cutting Object",FIELD_STRING,0.0,0.0,"");
- d->SetTitle("Derive Spline of Intersection");
-
- if (!d->DoDialog()) return FALSE;
-
- var objB = doc->FindObject(d->GetData(0));
-
- if(!objB || !instanceof(objB, PolygonObject))
- {
- TextDialog("Must select a polygon object to cut with!", DLG_OK);
- return;
- }
-
- var copyA = copy(doc, objA, "tempA");
- var copyB = copy(doc, objB, "tempB");
-
- cut_A_with_B(doc, NULL, copyA, copyB);
-
- doc->KillObject(copyA);
- doc->KillObject(copyB);
- doc->SendMessage(DOCUMENT_CHANGED);
- StatusClear();
- }
-
- fillet(doc)
- {
- var d = new (SimpleDialog);
-
- d->SetData(0,"Object A",FIELD_STRING,0.0,0.0,"");
- d->SetData(1,"Object B",FIELD_STRING,0.0,0.0,"");
- d->SetData(2,"Fillet Radius",FIELD_FLOAT,-1000000.0,1000000.0,20.0);
- d->SetData(3,"Number of Steps",FIELD_INTEGER,1,20,1);
- d->SetTitle("Derive Fillet Splines");
-
- if (!d->DoDialog()) return FALSE;
-
- var objA = doc->FindObject(d->GetData(0));
- var objB = doc->FindObject(d->GetData(1));
- var radius = d->GetData(2);
- var steps = d->GetData(3);
-
- if(!objA || !objB || !instanceof(objA, PolygonObject) || !instanceof(objB, PolygonObject))
- {
- TextDialog("Must select two polygon objects!", DLG_OK);
- return;
- }
-
- var group = doc->NewPolygonObject("Fillet Group",NULL,NULL,0,0,0,0);
-
- var i;
-
- for (i=0; i<=steps; i++)
- {
- var angle = (PI / 2.0) * float(i) / float(steps);
- var copyA = doInflate(doc, objA, (1 - cos(angle)) * radius);
- var copyB = doInflate(doc, objB, (1 - sin(angle)) * radius);
-
- if (i < (steps+1)/2)
- {
- cut_A_with_B(doc, group, copyA, copyB);
- }
- else
- {
- cut_A_with_B(doc, group, copyB, copyA);
- }
-
- doc->KillObject(copyA);
- doc->KillObject(copyB);
- }
- group->UpdateObject();
- doc->SendMessage(DOCUMENT_CHANGED);
- StatusClear();
- }
-
- main()
- {
- RegisterMenuHook("Spline of Intersection","intersect");
- RegisterMenuHook("Inflate","inflate");
- RegisterMenuHook("Fillet","fillet");
- }
-